home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * ObjectMacZapp -- a standard Mac OOP application template
- *
- *
- *
- * ZTextWindow.cpp -- a window that displays text files (uses TextEdit)
- *
- *
- *
- *
- *
- * © 1996, Graham Cox
- *
- *
- *
- *
- *************************************************************************************************/
-
-
-
- #include "ZTextWindow.h"
- #include "MacZoop.h"
-
- #include <TextEdit.h>
-
- static pascal Boolean ztClickproc();
- static ZTextWindow* gClickedTE;
- static TEClickLoopUPP gTEClickLoopCallBack = NewTEClickLoopProc( ztClickproc );
-
-
- CLASSCONSTRUCTOR( ZTextWindow );
-
-
- ZTextWindow::ZTextWindow( ZCommander* aBoss, short windID, Boolean allowEditing )
- : ZScroller( aBoss, windID, TRUE, TRUE )
- {
- itsText = NULL;
- isEditable = allowEditing;
- wControl = teWindowWidth;
- emWidth = 255;
- }
-
-
- ZTextWindow::ZTextWindow()
- : ZScroller()
- {
- itsText = NULL;
- isEditable = FALSE;
- wControl = teWindowWidth;
- emWidth = 255;
- }
-
-
-
- ZTextWindow::~ZTextWindow()
- {
- if ( itsText )
- TEDispose( itsText );
- }
-
-
- void ZTextWindow::InitZWindow()
- {
- ZScroller::InitZWindow();
-
- MakeTextEdit();
- }
-
-
- void ZTextWindow::DrawContent()
- {
- Rect r;
-
- SetOrigin( 0, 0 );
- GetContentRect( &r );
- ClipRect( &r );
-
- TEUpdate( &r, itsText );
- }
-
-
- void ZTextWindow::ClickContent( const Point mouse, const short modifiers )
- {
- if ( isEditable )
- {
- Point tm = mouse;
-
- SetOrigin( 0, 0 );
-
- if ( hasVBar )
- tm.v -= GetControlValue( theVBar );
-
- if ( hasHBar )
- tm.h -= GetControlValue( theHBar );
-
- gClickedTE = this;
- ClipRect( &(*itsText)->viewRect );
- TEClick( tm, (modifiers & shiftKey) == shiftKey, itsText );
- }
- }
-
-
- void ZTextWindow::Activate()
- {
- ZScroller::Activate();
-
- if ( gFontMenuID )
- gMenuBar->EnableCommand( gFontMenuID, 0 );
-
- if ( isEditable )
- TEActivate( itsText );
- }
-
-
- void ZTextWindow::Deactivate()
- {
- if ( isEditable )
- TEDeactivate( itsText );
-
- if ( gFontMenuID )
- gMenuBar->DisableCommand( gFontMenuID, 0 );
-
- ZScroller::Deactivate();
- }
-
-
- void ZTextWindow::Idle()
- {
- if ( isEditable )
- TEIdle( itsText );
- }
-
-
- void ZTextWindow::AdjustCursor( const Point mouse, const short modifiers )
- {
- Rect content;
-
- if ( isEditable )
- {
- GetContentRect( &content );
-
- if ( PtInRect( mouse, &content ))
- SetCursorShape( iBeamCursor );
- else
- SetCursorShape( 0 );
- }
- }
-
-
- void ZTextWindow::UpdateMenus()
- {
- if ( isEditable )
- {
- if ((*itsText)->selStart < (*itsText)->selEnd )
- {
- gMenuBar->EnableCommand( kCmdCut );
- gMenuBar->EnableCommand( kCmdCopy );
- gMenuBar->EnableCommand( kCmdClear );
- }
-
- gMenuBar->EnableCommand( kCmdSelectAll );
-
- // Font/style menus:
-
- TEStyleRunInfo ri;
-
- TEGetStyleRunInfo( &ri, itsText );
-
- // check sizes, styles & font
-
- gMenuBar->UpdateFontSizeMenu( &ri );
- gMenuBar->UpdateStyleMenu( &ri );
- }
-
- ZScroller::UpdateMenus();
- }
-
-
- void ZTextWindow::HandleCommand( const long aCmd )
- {
- // handle font size and style commands
-
- TextStyle newStyle;
- Boolean wasChanged = TRUE;
-
- switch( aCmd )
- {
- case kCmdPlainText:
- newStyle.tsFace = normal;
- TESetStyle( doFace, &newStyle, true, itsText );
- break;
-
- case kCmdBoldText:
- newStyle.tsFace = bold;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdItalicText:
- newStyle.tsFace = italic;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdUnderlineText:
- newStyle.tsFace = underline;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdOutlineText:
- newStyle.tsFace = outline;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdShadowText:
- newStyle.tsFace = shadow;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdCondensedText:
- newStyle.tsFace = condense;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdExtendedText:
- newStyle.tsFace = extend;
- TESetStyle( doFace + doToggle, &newStyle, true, itsText );
- break;
-
- case kCmdStdFontSize7:
- case kCmdStdFontSize9:
- case kCmdStdFontSize10:
- case kCmdStdFontSize12:
- case kCmdStdFontSize14:
- case kCmdStdFontSize18:
- case kCmdStdFontSize24:
- case kCmdStdFontSize36:
- case kCmdStdFontSize48:
- case kCmdStdFontSize60:
- case kCmdStdFontSize72:
- newStyle.tsSize = aCmd - kStdFontSizeBase;
- TESetStyle( doSize, &newStyle, true, itsText );
- break;
-
- default:
- ZScroller::HandleCommand( aCmd );
- wasChanged = FALSE;
- break;
- }
-
- if ( wasChanged )
- {
- dirty = TRUE;
- RecalText();
- }
- }
-
-
-
- void ZTextWindow::HandleCommand( const short menuID, const short itemID )
- {
- if ( menuID == gFontMenuID ) // Found font menu! Select our font:
- {
- Str255 itemName;
- TextStyle newStyle;
-
- GetMenuItemText( GetMenuHandle( gFontMenuID ), itemID, itemName );
- GetFNum( itemName, &newStyle.tsFont );
- TESetStyle( doFont, &newStyle, true, itsText );
- }
- else
- ZScroller::HandleCommand( menuID, itemID );
- }
-
-
-
- Boolean ZTextWindow::CanPasteType()
- {
- return isEditable && gClipboard->QueryType( 'TEXT' );
- }
-
-
- void ZTextWindow::DoCut()
- {
- if ( isEditable )
- {
- gClipboard->Clear();
- TECut( itsText );
- TEToScrap();
- RecalText();
- }
- }
-
-
- void ZTextWindow::DoCopy()
- {
- if ( isEditable )
- {
- gClipboard->Clear();
- TECopy( itsText );
- TEToScrap();
- }
- }
-
-
- void ZTextWindow::DoPaste()
- {
- if ( isEditable )
- {
- TEFromScrap();
- TEPaste( itsText );
- RecalText();
- }
- }
-
-
- void ZTextWindow::DoClear()
- {
- if ( isEditable )
- {
- TEDelete( itsText );
- RecalText();
- }
- }
-
-
- void ZTextWindow::DoSelectAll()
- {
- if ( isEditable )
- TESetSelect( 0, 32767, itsText );
-
- }
-
-
-
- void ZTextWindow::SetSize( const short width, const short height )
- {
- short ph, pv, nph, npv;
-
- GetPosition( &ph, &pv );
-
- ZScroller::SetSize( width, height, FALSE );
-
- GetPosition( &nph, &npv );
-
- // if variable width, adjust the width to the new window size
-
- if ( wControl == teWindowWidth )
- {
- Rect r, cr;
-
- r = (*itsText)->destRect;
- GetContentRect( &cr );
-
- r.right = r.left + cr.right - cr.left;
-
- (*itsText)->destRect = r;
-
- Focus();
- InvalRect( &cr );
- }
-
- // if the resize caused a shift in position, we must scroll to correctly position the text
- // in the view. Normally ZScroller does this for us but text views are complicated by the
- // fact that TextEdit handles its own scrolling.
-
- RecalText();
-
- if ( nph != ph ||
- npv != pv )
- {
- TEScroll( ph - nph, pv - npv, itsText );
- Draw();
- }
- }
-
-
- void ZTextWindow::Zoom( const short partCode )
- {
- short ph, pv, nph, npv;
-
- GetPosition( &ph, &pv );
-
- ZScroller::Zoom( partCode );
-
- GetPosition( &nph, &npv );
-
- // if variable width, adjust the width to the new window size
-
- if ( wControl == teWindowWidth )
- {
- Rect r, cr;
-
- r = (*itsText)->destRect;
- GetContentRect( &cr );
-
- r.right = r.left + cr.right - cr.left;
-
- (*itsText)->destRect = r;
- }
-
- // perform the same trick as SetSize...
-
- RecalText();
-
- if ( nph != ph ||
- npv != pv )
- TEScroll( ph - nph, pv - npv, itsText );
-
- Draw();
- }
-
-
-
- void ZTextWindow::Scroll( const short dH, const short dV )
- {
- TEPinScroll( dH, dV, itsText );
- }
-
-
-
- void ZTextWindow::Type( const char theChar, const short modifiers )
- {
- if ( isEditable )
- {
- TEKey( theChar, itsText );
-
- dirty = TRUE;
-
- RecalText();
- }
- }
-
-
- void ZTextWindow::MakeTextEdit()
- {
- Rect destRect, viewRect;
- FontInfo fi;
-
- // the dest rect is the scrollbounds, but that hasn't been set yet.
- // the view rect is the content area by default
-
- Focus();
-
- TextFont( kFontIDGeneva );
- TextSize( 12 );
- GetFontInfo( &fi );
-
- emSpace = fi.widMax;
- GetTextViewRect( &viewRect );
-
- destRect = viewRect;
- destRect.right = destRect.left + ( emSpace * emWidth );
-
- FailNIL( itsText = TEStyleNew( &destRect, &viewRect ));
-
- TESetClickLoop( gTEClickLoopCallBack, itsText );
- SetBounds( destRect );
- RecalText();
- }
-
-
-
- void ZTextWindow::OpenFile( const OSType fType, Boolean isStationery )
- {
- FInfo fi;
- short refNum;
- long pSize;
- Handle temp = NULL;
-
- if ( macFile.vRefNum != kNoFile )
- {
- FailOSErr( FSpGetFInfo( &macFile, &fi ));
-
- if ( fi.fdType != 'TEXT' )
- FailOSErr( paramErr );
-
- FailOSErr( FSpOpenDF( &macFile, fsCurPerm, &refNum ));
-
- try
- {
- FailOSErr( GetEOF( refNum, &pSize ));
- if ( pSize > kMaxTextSize )
- FailOSErr( kTextFileTooBigErr );
-
- FailNIL( temp = NewHandle( pSize ));
-
- HLock( temp );
- FailOSErr( FSRead( refNum, &pSize, *temp ));
-
- // set the text in text edit
-
- TESetText( *temp, pSize, itsText );
- HUnlock( temp );
-
- DisposeHandle( temp );
- FSClose( refNum );
-
- // see if there is a 'styl' resource:
-
- refNum = FSpOpenResFile( &macFile, fsCurPerm );
-
- if ( refNum > 0 ) // If there's no resFork, no styles to look for:
- {
- UseResFile( refNum );
- temp = Get1Resource( 'styl', 128 );
-
- if ( temp && ( ResError() == noErr ))
- {
- TEUseStyleScrap( 0, pSize, (StScrpHandle) temp, FALSE, itsText );
- ReleaseResource( temp );
- }
-
- CloseResFile( refNum );
- }
- }
- catch( OSErr err )
- {
- FSClose( refNum );
-
- if ( temp )
- {
- HUnlock( temp );
- DisposeHandle( temp );
- }
- throw err;
- }
- }
- ZScroller::OpenFile( fType, isStationery );
-
- // set up the bounds, etc
-
- RecalText();
- Draw();
- }
-
-
-
- void ZTextWindow::SaveFile()
- {
- short refNum;
- long pSize;
- OSErr theErr;
- Handle text = NULL;
- char tState;
-
- if ( macFile.vRefNum != kNoFile )
- {
- theErr = FSpOpenDF( &macFile, fsCurPerm, &refNum );
-
- if ( theErr == fnfErr )
- {
- FailOSErr( FSpCreate( &macFile, gAppSignature, 'TEXT', 0 ));
- FSpCreateResFile( &macFile, gAppSignature, 'TEXT', 0 );
- FailOSErr( ResError() );
- FailOSErr( FSpOpenDF( &macFile, fsCurPerm, &refNum ));
- }
- else
- FailOSErr( theErr );
-
- try
- {
- FailNIL( text = (*itsText)->hText );
-
- pSize = GetHandleSize( text );
-
- tState = HGetState( text );
- HLock( text );
- FailOSErr( FSWrite( refNum, &pSize, *text ));
- HSetState( text, tState );
-
- FailOSErr( SetEOF( refNum, pSize ));
- FSClose( refNum );
-
- // Now save styles:
-
- short savedStart = (*itsText)->selStart;
- short savedEnd = (*itsText)->selEnd;
-
- (*itsText)->selStart = 0;
- (*itsText)->selEnd = (*itsText)->teLength;
-
- StScrpHandle styles = TEGetStyleScrapHandle( itsText );
-
- (*itsText)->selStart = savedStart;
- (*itsText)->selEnd = savedEnd;
-
- refNum = FSpOpenResFile( &macFile, fsCurPerm );
-
- if( refNum > 0 )
- {
- Handle theRes = Get1Resource( 'styl', 128 );
-
- if( theRes )
- RemoveResource( theRes );
-
- AddResource((Handle) styles, 'styl', 128, "\p" );
- WriteResource((Handle) styles );
- ReleaseResource((Handle) styles );
- }
-
- CloseResFile( refNum );
- }
- catch( OSErr err )
- {
- FSClose( refNum );
- if ( text )
- HSetState( text, tState );
- throw err;
- }
- ZScroller::SaveFile();
- }
- }
-
-
- void ZTextWindow::RecalText()
- {
- static Boolean rtInProgress = FALSE;
-
- Rect content, tBounds, vRect;
- short textHeight, lineHeight;
-
- if ( ! rtInProgress )
- {
- rtInProgress = TRUE;
-
- Focus();
- SetOrigin( 0, 0 );
- GetContentRect(&content);
- (*itsText)->viewRect = content;
-
- TECalText( itsText );
- lineHeight = TEGetHeight( 1, 1, itsText );
- textHeight = TEGetHeight( 0, 32767 , itsText );
-
- GetBounds( &tBounds );
- tBounds.bottom = textHeight;
-
- if( wControl == teWindowWidth )
- tBounds.right = tBounds.left + content.right - content.left;
-
- SetBounds( tBounds );
-
- vRect = (*itsText)->destRect;
- OffsetRect( &tBounds, vRect.left - tBounds.left, vRect.top - tBounds.top );
- (*itsText)->destRect = tBounds;
-
- SetScrollAmount( emSpace, lineHeight );
-
- TEAutoView( TRUE, itsText );
- TESelView( itsText );
- TEAutoView( FALSE, itsText );
-
- if ( hasVBar )
- SetControlValue( theVBar, (*itsText)->viewRect.top - (*itsText)->destRect.top );
-
- if ( hasHBar )
- SetControlValue( theHBar, (*itsText)->viewRect.left - (*itsText)->destRect.left );
-
- rtInProgress = FALSE;
- }
- }
-
-
- void ZTextWindow::SetWidthControl( TEWidthControl aCtl, short fixWidth )
- {
- // this changes the text width control of the view. The default is a fixed width of 255 characters
- // of the max width of the default font. This is quite a good setting for e.g. code listings.
- // However, for text such as Read Me docs, etc, a variable width is probably more useful. In that
- // case the text view is adjusted to the current width of the window.
-
- if ( aCtl != wControl )
- {
- wControl = aCtl;
-
- if ( wControl == teFixedWidth )
- emWidth = fixWidth;
-
- // change the destRect of the text so that it is correct for the behaviour we are
- // selecting.
-
- if ( itsText )
- {
- Rect r = (*itsText)->destRect;
- Rect cr;
-
- if ( wControl == teWindowWidth )
- {
- GetContentRect( &cr );
- r.right = r.left + cr.right - cr.left;
- }
- else
- r.right = r.left + ( emSpace * emWidth );
-
- (*itsText)->destRect = r;
-
- RecalText();
- Draw();
- }
- }
- }
-
-
- void ZTextWindow::SetSizeRect( const Rect& szRect )
- {
- ZScroller::SetSizeRect( szRect );
-
- // if variable width, allow user to drag window regardless of bounds:
-
- if ( wControl == teWindowWidth )
- {
- sizeRect.right = 10000;
- sizeRect.bottom = 10000;
- }
- }
-
-
- void ZTextWindow::TextEditClickLoop()
- {
- // perform autoscrolling. This is the default click loop action- you can override it
- // if you want to do something else in the click loop.
-
- Point mouse;
- Rect r;
-
- Focus();
- GetMouse( &mouse );
- AutoScroll( mouse );
- SetOrigin( 0, 0 );
- GetContentRect( &r );
- ClipRect( &r );
- }
-
-
- static pascal Boolean ztClickproc()
- {
- try
- {
- if ( gClickedTE )
- gClickedTE->TextEditClickLoop();
- }
- catch( OSErr err )
- {
- }
-
- return TRUE;
- }
-